有个hadoop集群的datanode节点,datanode rpc端口50010, netstat -antp|grep 50010会发现大量FIN_WAIT1状态的socket,且长时间不消失,看了socket的对端机器,发现同一个连接,显示的状态一直是established. 根据网上的资料,做了一个实验,重现了这个现象
datanode机器:
1 | #fin_wait, socket发送缓冲区大量堵包 |
对端机器:
1 | #established, socket接收端缓冲区大量堵包 |
server.cpp:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int main()
{
int sockSrv = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addrSrv;
addrSrv.sin_family = AF_INET;
addrSrv.sin_addr.s_addr = INADDR_ANY;
addrSrv.sin_port = htons(8765);
bind(sockSrv, (const struct sockaddr *)&addrSrv, sizeof(struct sockaddr_in));
listen(sockSrv, 2);
struct sockaddr_in addrClient;
int len = sizeof(struct sockaddr_in);
int sockConn = accept(sockSrv, (struct sockaddr *)&addrClient, (socklen_t*)&len);
while(1)
{
// server端,如果不执行会车,会导致server一直阻塞在这里,不消费socket接收缓冲区,造成接收缓冲区堵塞
getchar();
char szRecvBuf[50001] = {0};
int iRet = recv(sockConn, szRecvBuf, sizeof(szRecvBuf) - 1, 0);
printf("iRet is %d\n", iRet);
}
close(sockConn);
close(sockSrv);
return 0;
}
// g++ server.cpp -o server
client.cpp:
1 |
|
这里如果多个client发起请求,netstat -antp|grep 8765, listen socket会看到recv-q数值会不断增大(代表current syn backlog),因为新的客户端请求并没有accept去处理,server端,新的socket的接收缓冲区也会会不断增大(tcpdump抓包看到新连接的三次握手已经完成,server端socket接收缓冲区已经在堆积,在缓冲区未满,还是能接收客户端发过来的数据,但是无法消费)。这个时候,即使client退出,server端listen socket的 syn backlog也不会减少。
1 | tcp 3 0 0.0.0.0:8765 0.0.0.0:* LISTEN 20479/./server |
单个客户端不断回车发送消息给服务端,服务端socket如果接收缓冲区未满,会接收数据,并回复确认包,这个过程中,server端socket接收缓冲区不断堆积,告知客户端端滑动窗口先会上升,然后慢慢下降,因为缓冲区可用空间在不断下降。同时,如果server端socket接收窗口变为0后,client继续发送包,无法送到server端, 会看到client端socket 发送缓冲区开始堵包。
1 | # tcpdump -i eth0 port 8765 |